package com.example.mysql.lock;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.HashMultimap;
import com.example.mysql.trx.Trx;
import com.example.mysql.trx.TrxSys;

import java.util.List;
import java.util.Set;

/**
 * wzy:wzynov@qq.com
 */
public class LockSys {

    public static HashMultimap<RecId, Lock> rec_hash = HashMultimap.create();

    public static boolean[][] lock_compatibility_matrix = new boolean[][] {
        /**                       IS     IX       S     X       AI */
        /* IS */ new boolean[] {  true,  true,  true,  false,  true},
        /* IX */ new boolean[] {  true,  true,  false, false,  true},
        /* S  */ new boolean[] {  true,  false, true,  false,  false},
        /* X  */ new boolean[] {  false, false, false, false,  false},
        /* AI */ new boolean[] {  true,  true,  false, false,  false}
    };

    public static Set<Lock> getLock(RecId recId) {
        return rec_hash.get(recId);
    }

    public static void addLock(RecId recId, Lock lock) {
        rec_hash.put(recId, lock);
        TrxSys.trxThreadLocal.get().addLock(lock);
    }

    public static void lock_rec_grant(Trx trx) {
        List<Lock> trxLocks = trx.getLocks();

        if (CollUtil.isNotEmpty(trxLocks)) {
            // 先把事务中的锁从锁系统中移除掉
            for (Lock trxLock : trxLocks) {
                LockSys.rec_hash.remove(trxLock.getRecId(), trxLock);
            }

            // 再判断其他锁是否可以解阻塞，只需要判断对应记录的锁
            for (Lock trxLock : trxLocks) {
                for (Lock lock : LockSys.getLock(trxLock.getRecId())) {
                    // 只需要判断正在等待的锁，如果不需要继续等待，则可以唤醒该lock了
                    if (lock.isWait() && !lock_rec_has_to_wait_in_queue(lock)) {
                        synchronized (lock.getLock()) {
                            lock.getLock().notify();
                        }
                    }
                }
            }
        }

    }

    public static boolean lock_rec_has_to_wait_in_queue(Lock lock) {
        for (Lock otherLock : getLock(lock.getRecId())) {
            if (lock.equals(otherLock)) {
                // 遍历到自己，那就证明自己之前的锁和自己是不冲突的，自己可以释放，不需要等待
                break;
            } else {
                // 如果不是自己则需要判断兼容性，不兼容则返回true，表示需要继续等待
                if (!lock_compatibility_matrix[LockSys.getLockMode(lock.getMode())][LockSys.getLockMode(otherLock.getMode())]) {
                    return true;
                }
            }
        }
        return false;
    }

    public static int getLockMode(int mode) {
        return mode & 0xF;
    }

    public static void main(String[] args) {
        HashMultimap<String, String> hashMultimap = HashMultimap.create();
        hashMultimap.put("1", "11");
        hashMultimap.put("1", "12");
        Set<String> strings = hashMultimap.get("1");
        System.out.println(strings);

    }


}
